﻿using System.Collections.Generic;
using System.Common;
using System.ComponentModel;
using System.Reflection;

namespace System
{
    /// <summary>
    /// 枚举的扩展
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Never)]
    public static class EnumExtension
    {
        private static readonly Dictionary<Type, List<Description>> EnumDescriptionCache = new Dictionary<Type, List<Description>>();
        private static readonly object LockObject = new object();

        #region Bool 判断
        /// <summary>
        /// 检测枚举是否包含指定成员
        /// </summary>
        /// <typeparam name="T">枚举名,比如Enum1</typeparam>
        /// <param name="member">枚举成员名或成员值</param>
        public static bool IsDefined<T>(string member)
        {
            return Enum.IsDefined(typeof(T), member);
        }

        #endregion //Bool 判断

        #region EnumName

        #endregion //EnumName

        #region Description
        /// <summary>
        /// 获得描述
        /// </summary>
        /// <param name="type">枚举类型参数</param>
        /// <returns></returns>
        public static List<Description> GetEnumDescriptions(this Type type)
        {
            if (type == null || type.BaseType != typeof(Enum)) throw new InvalidOperationException();

            var result = EnumDescriptionCache.GetValue(type);
            if (result == null)
            {
                lock (LockObject)
                {
                    if (result == null)
                    {
                        var fields = type.GetFields();
                        result = new List<Description>(fields.Length);

                        foreach (var f in fields)
                        {
                            if (f.IsSpecialName || !f.IsPublic) continue;

                            var value = f.GetRawConstantValue();
                            var typeWrapper = (MemberDescriptorBase)f;

                            //创建泛型类
                            var m = typeof(DescriptionGeneric<>).MakeGenericType(type);
                            var desc = (Description)Activator.CreateInstance(m, typeWrapper.DisplayName, typeWrapper.Description, value, f);

                            result.Add(desc);
                        }

                        EnumDescriptionCache.Add(type, result);
                    }
                }
            }

            return result;
        }

        /// <summary>
        /// 获得描述
        /// </summary>
        /// <returns></returns>
        public static List<DescriptionGeneric<T>> GetEnumDescriptions<T>()
        {
            var type = typeof(T);

            if (type.BaseType != typeof(Enum)) throw new InvalidOperationException();

            var fields = type.GetFields();
            var list = new List<DescriptionGeneric<T>>(fields.Length);

            foreach (var f in fields)
            {
                if (f.IsSpecialName || !f.IsPublic) continue;

                var value = f.GetRawConstantValue();
                var typeWrapper = (MemberDescriptorBase)f;

                list.Add(new DescriptionGeneric<T>(typeWrapper.DisplayName, typeWrapper.Description, value, f));
            }

            return list;
        }

        /// <summary>
        ///     根据枚举对象获取枚举描述
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public static string GetDescription<T>(T t) where T : struct
        {
            return GetDescription(typeof(T), t);
        }

        /// <summary>
        /// 根据枚举索引获取枚举描述
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="enumIndex"></param>
        /// <returns></returns>
        public static string GetDescription<T>(int enumIndex) where T : struct
        {
            return GetDescription(typeof(T), enumIndex);
        }

        /// <summary>
        /// 根据枚举名称获取枚举描述
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="enumName"></param>
        /// <returns></returns>
        public static string GetDescription<T>(string enumName) where T : struct
        {
            return GetDescription(typeof(T), enumName);
        }

        /// <summary>
        ///     获取枚举描述  请尽量使用 GetDescription<T> 方法
        /// </summary>
        /// <param name="type">枚举类型</param>
        /// <param name="enumParameter">支持枚举对象、枚举数值、枚举名称</param>
        /// <returns></returns>
        public static string GetDescription(Type type, object enumParameter)
        {
            if (type == null)
                return string.Empty;

            string result = string.Empty;

            if (enumParameter == null)
                return result;

            List<EnumContext> contextList = BuildEnumContext(type);
            if (contextList == null || contextList.Count == 0)
                return result;

            if (enumParameter is int)
            {
                int enumIndex = Convert.ToInt32(enumParameter);
                EnumContext context = contextList.Find(item => item.EnumIndex == enumIndex);
                if (context != null)
                    result = context.Description;
            }
            else
            {
                string enumName = enumParameter + "";
                EnumContext context = contextList.Find(item => enumName.Equals(item.EnumValue, StringComparison.CurrentCultureIgnoreCase));
                if (context != null)
                    result = context.Description;
            }
            return result;
        }

        /// <summary>
        /// 返回枚举类型中枚举名称为enumObjectName的描述
        /// </summary>
        /// <param name="infoArray"></param>
        /// <param name="enumName"></param>
        /// <returns></returns>
        static string FindDescription(FieldInfo[] infoArray, string enumName)
        {
            string result = string.Empty;

            foreach (FieldInfo info in infoArray)
            {
                if (!info.IsSpecialName && info.Name.Equals(enumName, StringComparison.CurrentCultureIgnoreCase))
                {
                    object[] customAttributes = info.GetCustomAttributes(typeof(DescriptionAttribute), false);
                    if (customAttributes != null && customAttributes.Length > 0)
                    {
                        result = ((DescriptionAttribute)customAttributes[0]).Description;
                        break;
                    }
                }
            }
            if (string.IsNullOrEmpty(result))
            {
                result = enumName;
            }
            return result;
        }
        #endregion //Description

        #region EnumObject

        #endregion //EnumObject

        #region EnumIndex

        static int GetEnumObjectIndex(Type type, string enumName)
        {
            int result = -1;

            if (Enum.IsDefined(type, enumName))
            {
                object enumObject = Enum.Parse(type, enumName, true);
                if (enumObject != null)
                    result = (int)enumObject;
            }
            return result;
        }
        #endregion //EnumIndex


        #region Methods

        /// <summary>
        /// 获取枚举的基础类型
        /// </summary>
        /// <param name="enumType">枚举类型</param>
        public static Type GetUnderlyingType(Type enumType)
        {
            //获取基础类型
            return Enum.GetUnderlyingType(enumType);
        }

        static List<EnumContext> BuildEnumContext(Type type)
        {
            List<EnumContext> result = new List<EnumContext>();
            string[] nameArray = Enum.GetNames(type);
            FieldInfo[] infoArray = type.GetFields();

            foreach (string item in nameArray)
            {
                result.Add(new EnumContext
                {
                    EnumValue = item,
                    EnumIndex = GetEnumObjectIndex(type, item),
                    Description = FindDescription(infoArray, item)
                });
            }
            return result;
        }

        #endregion //Private Methods
    }
}